grammar compile;

options {
  language=Java;
}
 
 /*
  lacking
    -> printing the result of the funcCall
 */
prog        :   constant* function* main;

//constant
constant    :   'const' DATATYPE IDENTIFIER '=' exp ';' '\n'* | 
                'const' ARRTYPE IDENTIFIER '=' BEGIN arr_value END  ';' '\n'*; 

function    :   DATATYPE IDENTIFIER '(' params ')' BEGIN declaration* stmt END '\n'*
            |   'void' IDENTIFIER '(' params ')' BEGIN declaration* stmt END '\n'*
            
            |   DATATYPE IDENTIFIER '()' BEGIN declaration* stmt END '\n'*
            |   'void' IDENTIFIER '()' BEGIN declaration* stmt END '\n'*
            ;

params      : DATATYPE IDENTIFIER ',' params | DATATYPE IDENTIFIER;

main        :   'main' '()' BEGIN declaration* stmt END;

declaration :   norm_dec| arr_dec;

norm_dec    :   DATATYPE IDENTIFIER '=' exp ';' 
            |   DATATYPE IDENTIFIER CREMENT exp
            |   DATATYPE IDENTIFIER ';';
            
arr_dec     :   ARRTYPE IDENTIFIER '=' BEGIN arr_value END ';'
            |   ARRTYPE IDENTIFIER '=' DATATYPE '['INT']' ';';

stmt        :   line* '\n'* ;//| '\t'* BEGIN line* END '\n'*;
line        :   assign | input | output
            |   ifStmt|whileStmt| forStmt| doWhileStmt| funcCall ';'| returnExp| BEGIN stmt END;


assign      :   IDENTIFIER '=' exp ';'| IDENTIFIER CREMENT exp ';';

//input & output
input       :   'scanf' '(' '"' type '"' ',' '&' IDENTIFIER ')' ';'
            |   'scanf' '(' '"' type '"' ',' '&' IDENTIFIER '[' INT']' ')' ';';

output      :   'printf' '('  STRING  ')' ';'
            |   'printf' '(' '"' typeList '"' ',' varList ')' ';';
   
typeList    :   type typeList| type;
type        :   '%c'| '%d'|'%f'| '%s';                
varList     :   IDENTIFIER ',' varList
            |   IDENTIFIER;
   
//Conditional
ifStmt      :   'if' '(' condExp ')' BEGIN stmt END elseStmt;

elseStmt    :   'else' BEGIN stmt END;


//Loops
whileStmt   :   'while' '(' condExp ')' BEGIN stmt END;

forStmt     :   'for' '(' norm_dec condExp ';' crement ')' BEGIN stmt END;

crement     :   IDENTIFIER PLUSMIN
            |   IDENTIFIER CREMENT value
            |   IDENTIFIER CREMENT IDENTIFIER ;

doWhileStmt :   'do' BEGIN stmt END 'while(' condExp ')' ';';

//functionCall
funcCall    :   IDENTIFIER '(' argument ')'| IDENTIFIER '()';

argument    :   value ',' argument
            |   IDENTIFIER ',' argument
            |   value| IDENTIFIER ;

returnExp   :   'return' exp ';';

condExp     :    innerCond ('&&' innerCond)*;
innerCond   :    cond ('||' cond)*;
cond        :    IDENTIFIER EQUATE value| IDENTIFIER EQUATE IDENTIFIER 
            |     value EQUATE IDENTIFIER
            |  '(' condExp ')' ;
 
 
                

arr_value   :   value ',' arr_value| value;
value       :   INT|FLOAT|STRING|CHAR;
valArr      :   IDENTIFIER '[' INT ']';

exp         :   innerExp ('+' innerExp | '-' innerExp)*;
innerExp    :   atom ('*' atom | '/' atom )*;
atom        :   value | '(' exp ')'| IDENTIFIER| valArr| funcCall;

//stuff
BEGIN       :   '{';
END         :   '}';

DATATYPE    :   'int'| 'float'|'String'| 'char';
ARRTYPE     :   'int[]'| 'float[]'| 'String[]'| 'char[]';
FUNCTIONNAME:   ('A'..'Z') ('a'..'z'| 'A'..'Z'| '0'..'9'| '_')*;
CREMENT     :   '+=' | '-='|'/='|'*='; 

EQUATE      :   '==' | '<='| '>='| '<'| '>'| '!=';
PLUSMIN     :   '++'| '--';

IDENTIFIER  :   ('a'..'z' | '_') ('a'..'z'| 'A'..'Z'| '0'..'9'| '_')* ;
INT         :   '0'..'9'+;
FLOAT       :   INT '.' '0'..'9'*;
STRING      :   '"' ('a'..'z'|'A'..'Z' | '0'..'9'| ' ')* '"';
CHAR        :   '\'' ('a'..'z'|'A'..'Z' | '0'..'9'| ' ') '\'';

// Whitespace and comments
COMMENT     :  '//' ~('\r' | '\n')* {$channel = HIDDEN;}
            |  '/*' .* '*/'         {$channel = HIDDEN;}
            ;

WS          :   ( '\t' | ' ' | '\r' | '\n'| '\u000C' )+  { $channel = HIDDEN; } ;
NEWLINE     :   '\n'* {$channel = HIDDEN;};